#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>

#include "tgtdefs.h"
#include "nrfutils.h"

#include "matrix.h"
#include "keycode.h"

#define ROW_MASK_ALL		0b01000111
#define COL_MASK_ALL		0b01111100

const __code uint8_t row_mask[NUM_ROWS] =
{
	0b00000001,
	0b00000010,
	0b00000100,
	0b01000000,
};

const __code uint8_t col_mask[NUM_COLS] = 
{
	0b00000100,
	0b00001000,
	0b00010000,
	0b00100000,
	0b01000000,
};

// the state of the key matrix
uint8_t matrix[NUM_ROWS];

// contains the number of keys that are currently down
// this value is refreshed in matrix_scan()
uint8_t matrix_num_keys_pressed = 0;

void matrix_on(void)
{
	P0DIR = 0b00000000;		// output
	P1DIR = 0b01111100;		// inputs
}

void matrix_off(void)
{
	P0DIR = 0b11111111;		// all inputs
	P1DIR = 0b11111111;
}

void matrix_init(void)
{
	uint8_t row;
	for (row = 0; row < NUM_ROWS; ++row)
		matrix[row] = 0;

	matrix_on();
}

bool matrix_scan(void)
{
	bool has_changes = false;
	uint8_t row, col;

	// check if we have any buttons down
	
	P0 &= ~ROW_MASK_ALL;	// drive outputs
	
	if ((P1 & COL_MASK_ALL) == COL_MASK_ALL)
	{
		// all buttons are up
		if (matrix_num_keys_pressed != 0)
		{
			for (row = 0; row < NUM_ROWS; row++)
			{
				if (matrix[row])
				{
					matrix[row] = 0;
					has_changes = true;
				}
			}
		}

		matrix_num_keys_pressed = 0;
		
	} else {

		matrix_num_keys_pressed = 0;
		
		// at least one button is down
		for (row = 0; row < NUM_ROWS; row++)
		{
			// drive the outputs
			P0 = (P0 & ~ROW_MASK_ALL) | (ROW_MASK_ALL ^ row_mask[row]);
			
			for (col = 0; col < NUM_COLS; col++)
			{
				// get the states
				bool curr_state = (P1 & col_mask[col]) == 0;
				bool prev_state = matrix[row] & _BV(col);

				// increment the number of keys pressed
				if (curr_state)
					++matrix_num_keys_pressed;
				
				// update the matrix if needed
				if (curr_state != prev_state)
				{
					matrix[row] ^= _BV(col);
					has_changes = true;
				}
			}
		}
	}

	return has_changes;
}

uint8_t get_num_keys_pressed(void)
{
	return matrix_num_keys_pressed;
}
